package com.xbongbong.paas.outerlink;

import com.alibaba.dingtalk.openapi.helper.Env;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.outLink.domain.entity.OuterLinkConfigEntity;
import com.xbongbong.outLink.domain.entity.OuterLinkEntity;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.constant.TimeConstant;
import com.xbongbong.paas.data.service.RichTextService;
import com.xbongbong.paas.data.service.SerialNoService;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.ext.ConditionsEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasFormDataEsModel;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.enums.ConditionEnum;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.PlatFormEnum;
import com.xbongbong.paas.enums.SheetTypeEnum;
import com.xbongbong.paas.enums.clazz.ConditionClass;
import com.xbongbong.paas.field.DefaultAttrPoJo;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.ItemPoJo;
import com.xbongbong.paas.field.SubFormPoJo;
import com.xbongbong.paas.form.AbstractFormService;
import com.xbongbong.paas.help.FormExplainHelp;
import com.xbongbong.sys.help.PackageHelp;
import com.xbongbong.paas.help.ProFormHelp;
import com.xbongbong.paas.help.ProSaveHelp;
import com.xbongbong.paas.log.entity.OutLinkQueryLogEntity;
import com.xbongbong.paas.log.model.OutLinkQueryLogModel;
import com.xbongbong.paas.model.OuterLinkConfigModel;
import com.xbongbong.paas.model.OuterLinkModel;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.outerlink.interfaces.PaasOuterLinkConfigService;
import com.xbongbong.paas.outerlink.interfaces.PaasOuterLinkService;
import com.xbongbong.paas.pojo.OutLinkFieldAttrEntity;
import com.xbongbong.paas.pojo.dto.ActiveRuleDTO;
import com.xbongbong.paas.pojo.dto.FormDataAddDTO;
import com.xbongbong.paas.pojo.dto.FormDataListDTO;
import com.xbongbong.paas.pojo.dto.OuterLinkAddDTO;
import com.xbongbong.paas.pojo.dto.OuterLinkAddGetDTO;
import com.xbongbong.paas.pojo.dto.OuterLinkAppearanceGetDTO;
import com.xbongbong.paas.pojo.dto.OuterLinkBaseDTO;
import com.xbongbong.paas.pojo.dto.OuterLinkListDTO;
import com.xbongbong.paas.pojo.dto.ParseSingleRowDataDTO;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.pojo.vo.AfterSaveVO;
import com.xbongbong.paas.pojo.vo.FormDataAddGetVO;
import com.xbongbong.paas.pojo.vo.FormDataAddVO;
import com.xbongbong.paas.pojo.vo.FormDataUpdateGetVO;
import com.xbongbong.paas.pojo.vo.PaasFormDataEsListVO;
import com.xbongbong.paas.pojo.vo.ParseSingleRowDataVO;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisConstant;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.util.URLEncodeUtils;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.paas.util.FormUtil;
import com.xbongbong.parent.explain.FormDataAddFormExplainHandlerName;
import com.xbongbong.parent.parse.data.FormDataListAnalysisDataHelp;
import com.xbongbong.parent.parse.data.FormDataUpdateGetAnalysisDataHelp;
import com.xbongbong.pro.businessdata.pojo.dto.FormatExplainDTO;
import com.xbongbong.pro.config.ProBaseConfig;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.domain.entity.FormConfigEntity;
import com.xbongbong.pro.domain.entity.LabelEntity;
import com.xbongbong.pro.enums.PackageStatusEnum;
import com.xbongbong.pro.enums.PackageTypeEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.ValueAddedTypeEnum;
import com.xbongbong.pro.enums.errorcodes.BuinessDefaultErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.OutLinkErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.form.pojo.dto.FormConfigGetDTO;
import com.xbongbong.pro.formdata.pojo.SaasNeedRedundantAttrPojo;
import com.xbongbong.pro.formexplain.pojo.HandleExplainPojo;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainDTO;
import com.xbongbong.pro.formexplain.pojo.vo.HandlerExplainVO;
import com.xbongbong.pro.outLink.pojo.OuterLinkAppearanceGetVO;
import com.xbongbong.pro.statistic.result.pojo.ElasticAggsPojo;
import com.xbongbong.pro.workorder.pojo.vo.WorkOrderDataEsListVO;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.enums.DingtalkPageUrlEnum;
import com.xbongbong.saas.enums.FormConfigEnum;
import com.xbongbong.saas.enums.ListGroupEnum;
import com.xbongbong.saas.enums.NumberTypeEnum;
import com.xbongbong.saas.enums.OutLinkAdvancedEnum;
import com.xbongbong.saas.enums.OutLinkSettingTypeEnum;
import com.xbongbong.saas.enums.OuterLinkTypeEnum;
import com.xbongbong.saas.enums.RepeatTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.business.PurchaseEnum;
import com.xbongbong.saas.enums.business.QuotationEnum;
import com.xbongbong.saas.enums.business.SalesOpportunityEnum;
import com.xbongbong.saas.enums.business.WorkReportTypeEnum;
import com.xbongbong.saas.help.FundHelp;
import com.xbongbong.saas.model.FormConfigModel;
import com.xbongbong.saas.model.IndexTypeModel;
import com.xbongbong.saas.model.LabelModel;
import com.xbongbong.saas.service.toolbox.help.AttrDecimalPrecisionHelper;
import com.xbongbong.saas.service.toolbox.help.PackageStatusHelp;
import com.xbongbong.saas.service.toolbox.help.SaasSaveHelper;
import com.xbongbong.util.AddressUtil;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;

/**
 * 外链抽象类
 * @author long.rao
 * @version v1.0
 * @date 2020/8/10 10:52
 * @since v1.0
 */
public abstract class AbstractPaasOuterLinkService extends AbstractFormService implements PaasOuterLinkService {

    private static final Logger LOG = LoggerFactory.getLogger(AbstractPaasOuterLinkService.class);

    private static final List<Integer> FILTER_ATTR = Arrays.asList(FieldTypeEnum.TEXT.getType(), FieldTypeEnum.NUM.getType(), FieldTypeEnum.DATETIME.getType(), FieldTypeEnum.RADIO_GROUP.getType(),
            FieldTypeEnum.COMBO.getType(), FieldTypeEnum.ADDRESS.getType(), FieldTypeEnum.SERIALNO.getType(), FieldTypeEnum.COMBO_CHECK.getType(), FieldTypeEnum.LABEL.getType());

    @Resource
    private OuterLinkModel outerLinkModel;
    @Resource
    private SaasSaveHelper saasSaveHelper;
    @Resource
    private OuterLinkConfigModel outerLinkConfigModel;
    @Resource
    private PaasOuterLinkConfigService outerLinkConfigService;
    @Resource
    private FormExplainHelp formExplainHelp;
    @Resource
    private FundHelp fundHelp;
    @Resource
    private FormDataUpdateGetAnalysisDataHelp formDataUpdateGetAnalysisDataHelp;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private FormDataAddFormExplainHandlerName formDataAddFormExplainHandlerName;
    @Resource
    private FormConfigModel formConfigModel;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private PackageStatusHelp packageStatusHelp;
    @Resource
    private PackageHelp packageHelp;
    @Resource
    private EsHelper esHelper;
    @Resource
    private AttrDecimalPrecisionHelper attrDecimalPrecisionHelper;
    @Resource
    private FormDataListAnalysisDataHelp formDataListAnalysisDataHelp;
    @Resource
    private ProFormHelp proFormHelp;
    @Resource
    private ProBaseConfig proBaseConfig;
    @Resource
    private IndexTypeModel indexTypeModel;

    @Resource
    private LabelModel labelModel;

    @Resource
    private OutLinkQueryLogModel outLinkQueryLogModel;

    @Resource
    private PaasFormDataEsModel paasFormDataEsModel;

    @Resource
    private SerialNoService serialNoService;

    @Resource
    private RichTextService richTextService;


    @Override
    public PaasFormDataEsListVO getList(OuterLinkListDTO outerLinkDTO) throws XbbException {
        String token = outerLinkDTO.getToken();
        OuterLinkEntity searchEntity = outerLinkModel.getByTokenAndType(token, OuterLinkTypeEnum.SEARCH.getCode());
        if (!Objects.equals(searchEntity.getEnable(), BasicConstant.ONE)) {
            throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405005);
        }
        String corpid = searchEntity.getCorpid();
        Long formId = searchEntity.getFormId();
        Integer businessType = searchEntity.getBusinessType();
        Integer saasMark = SaasMarkEnum.SAAS.getCode();
        //校验套餐类型
        Integer feeType = packageHelp.getFeeType(corpid);
        if (Objects.equals(feeType,PackageTypeEnum.STANDARD.getType())){
            throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405014);
        }
        if (Objects.equals(businessType, 0)) {
            saasMark = SaasMarkEnum.PAAS.getCode();
        }
        FormDataListDTO formDataListDTO = new FormDataListDTO();
        BeanUtil.copyProperties(outerLinkDTO, formDataListDTO);
        formDataListDTO.setCorpid(corpid);
        formDataListDTO.setBusinessType(businessType);
        formDataListDTO.setSaasMark(saasMark);
        formDataListDTO.setSubBusinessType(businessType);
        formDataListDTO.setFormId(formId);
        // 数据
        PaasFormDataEsListVO outerLinkListVO = this.getOuterLinkList(formDataListDTO,token);
        List<FieldAttrEntity> headList = outerLinkListVO.getHeadList();
        List<String> screens = getScreens(corpid, formId, headList);
        outerLinkListVO.setScreens(screens);
        Map<String, List<ConditionClass>> conditionMap = getConditionList();
        outerLinkListVO.setConditionList(conditionMap);

        return outerLinkListVO;
    }

    @Override
    public PaasFormDataEsListVO getOuterLinkList(FormDataListDTO formDataListDTO, String token) throws XbbException {
        PaasFormDataEsListVO paasFormDataEsListVO = new PaasFormDataEsListVO();
        //表单获取
        PaasFormEntityExt form = this.getForm(formDataListDTO.getCorpid(),formDataListDTO.getFormId(),formDataListDTO.getBusinessType());
        // 处理解释字段
        HandleExplainPojo handleExplainPojo = this.handlOuterLinkExplains(formDataListDTO,form);

        List<FieldAttrEntity> explainList = handleExplainPojo.getExplainList();
        // 里面是有对于condition为空判断，因为这是第一次进来，必须让数据为空，所以要在最前面判断
        // 对于condition的增减必须放在后面
        PaasFormDataEsListVO paasFormDataEsList = new PaasFormDataEsListVO();
        paasFormDataEsList.setUpdateTime(handleExplainPojo.getUpdateTime());
        paasFormDataEsList.setForm(form);
        paasFormDataEsList.setHeadList(explainList);
        if (CollectionsUtil.isEmpty(formDataListDTO.getConditions())) {
            PageHelper pageHelper = new PageHelper(formDataListDTO.getPage(), formDataListDTO.getPageSize());
            pageHelper.setRowsCount(0);
            paasFormDataEsList.setPageHelper(pageHelper);
            return paasFormDataEsList;
        }
        // 处理筛选条件
        formatListCondition(formDataListDTO);

        WorkOrderDataEsListVO workOrderDataEsListVO = new WorkOrderDataEsListVO();
        if (CollectionsUtil.isNotEmpty(explainList)) {
            boolean searchSubForm = false;
            List<String> subFiledAttr = new ArrayList<>();
            for (FieldAttrEntity item : explainList) {
                if (Objects.equals(item.getFieldType(), FieldTypeEnum.SUB_FORM.getType())) {
                    searchSubForm = true;
                    subFiledAttr.add(item.getAttr());
                }
            }
            formDataListDTO.setSearchSubForm(searchSubForm);
            formDataListDTO.setSubFieldList(subFiledAttr);
        }
        //数据查询
        if (Objects.equals(formDataListDTO.getBusinessType(), XbbRefTypeEnum.WORK_ORDER.getCode())) {
            workOrderDataEsListVO = paasFormDataEsModel.workOrderList(formDataListDTO);
            BeanUtil.copyProperties(workOrderDataEsListVO, paasFormDataEsListVO);
        } else {
            IndexTypeEnum indexTypeEnum = indexTypeModel.getIndexType(formDataListDTO.getCorpid(), formDataListDTO.getBusinessType(), formDataListDTO.getSaasMark());
            paasFormDataEsListVO = paasFormDataEsModel.list(formDataListDTO, indexTypeEnum);
        }
        paasFormDataEsListVO.setUpdateTime(handleExplainPojo.getUpdateTime());
        paasFormDataEsListVO.setForm(form);
        paasFormDataEsListVO.setHeadList(explainList);
        paasFormDataEsListVO.setExplainMap(formDataListDTO.getExplainMap());

        // 根据数据处理特殊表头
        handleExplainByDataList(explainList,form,paasFormDataEsListVO);

        this.handleDataList(formDataListDTO,paasFormDataEsListVO,workOrderDataEsListVO);


        //金额千份位解析,不放入底层以免移动端多次解析失败 单独拎出来
        formDataListAnalysisDataHelp.analysisAmountOfThousandBits(paasFormDataEsListVO, formDataListDTO.getAnalysisAmountOfThousandBitsWithOriginalValue());
        // 处理日期类型的问题
        this.handleDateField(paasFormDataEsListVO);

        // 外链查询日志
        String module = XbbRefTypeEnum.getByCode(formDataListDTO.getBusinessType()).getName();
        // 查询链接
        // 查询条件解析
        List<ConditionsEntityExt> conditionsEntityExts = formDataListDTO.getConditions();
        JSONArray jsonArray = new JSONArray();
        if(Objects.nonNull(conditionsEntityExts)){
            conditionsEntityExts.forEach(item -> {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("attr",item.getAttr());
                jsonObject.put("name",item.getName());
                jsonObject.put("value",item.getValue());
                jsonArray.add(jsonObject);
            });
        }
        OutLinkQueryLogEntity outLinkQueryLogEntity = new OutLinkQueryLogEntity(formDataListDTO.getCorpid(), formDataListDTO.getPlatform(),formDataListDTO.getBrowserInfo(),formDataListDTO.getIp(),JSONObject.toJSONString(jsonArray),token,module);
        try {
            outLinkQueryLogModel.insert(outLinkQueryLogEntity);
        } catch (XbbException e) {
            LOG.error("外链查询 添加查询日志出错 : ", e);
        }
        return paasFormDataEsListVO;
    }

    /**
     * 根据数据封装下字段解释
     * @param headList 字段解释
     * @param paasFormEntityExt 源数据
     * @param formDataListVO 回参
     * @return  List<FieldAttrEntity>
     */
    protected List<FieldAttrEntity> handleExplainByDataList(List<FieldAttrEntity> headList,  PaasFormEntityExt paasFormEntityExt, PaasFormDataEsListVO formDataListVO) throws XbbException{
        return headList;
    }


    @Override
    public HandleExplainPojo handlOuterLinkExplains(FormDataListDTO formDataListDTO, PaasFormEntityExt form) throws XbbException {
        String corpid = formDataListDTO.getCorpid();
        Integer businessType = formDataListDTO.getBusinessType();
        Long formId = form.getId();
        PaasFormExplainEntity paasFormExplainEntity = this.getFormExplain(corpid,formId,businessType);
        List<FieldAttrEntity> explainList = JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);
        ExplainUtil.filterSpecialAttr(explainList, OuterLinkTypeEnum.SEARCH.getCode(), null);
        List<String> fieldList = new ArrayList<>();
        for (FieldAttrEntity item : explainList) {
            // 外链查询不要汇总
            item.setSummaryFlag(0);
            // 外链查询不要排序
            item.setDisableListSort(1);
            // 外链查询不需要默认值属性，目前是因为公式属性造成值的改动了，所以这边去掉默认值
            item.setDefaultAttr(new DefaultAttrPoJo());
            item.setItems(proFormHelp.setItem(item, form));
            fieldList.add(item.getAttr());
        }
        // 过滤各业务特殊字段
        outerLinkConfigService.removeUnsupportedAttr(businessType,explainList,OuterLinkTypeEnum.SEARCH);

        OuterLinkConfigEntity permissionSetting = outerLinkConfigService.getOuterLinkConfigEntities(corpid, formId, OuterLinkTypeEnum.SEARCH.getCode(), OutLinkSettingTypeEnum.PERMISSION_SETTING.getCode());
        OuterLinkConfigEntity displaySetting = outerLinkConfigService.getOuterLinkConfigEntities(corpid, formId, OuterLinkTypeEnum.SEARCH.getCode(), OutLinkSettingTypeEnum.DISPLAY_SETTING.getCode());
        // 外链查询处理可见可编辑
        ExplainUtil.handelFieldPermission(explainList, permissionSetting, displaySetting);
        if (Objects.nonNull(displaySetting) && StringUtil.isNotEmpty(displaySetting.getDefaultFormName())) {
            form.setName(displaySetting.getDefaultFormName());
        }


        Map<String,FieldAttrEntity> explainMap = this.getExplainMap(explainList, paasFormExplainEntity.getBusinessType(), corpid,form.getId());

        formDataListDTO.setExplainMap(explainMap);
        HandleExplainPojo handleExplainPojo = new HandleExplainPojo();
        handleExplainPojo.setExplainList(explainList);
        handleExplainPojo.setFieldList(fieldList);
        handleExplainPojo.setUpdateTime(paasFormExplainEntity.getUpdateTime());
        return handleExplainPojo;
    }

    @Override
    public void handleDataList(FormDataListDTO formDataListDTO, PaasFormDataEsListVO paasFormDataEsListVO, WorkOrderDataEsListVO workOrderDataEsListVO) throws XbbException {
        formDataListAnalysisDataHelp.analysisOuterLinkDataList(formDataListDTO, paasFormDataEsListVO);
    }


    /**
     * 地址筛选条件
     *
     * @param formDataListDTO 参数
     * @return
     * @throws
     * @author hongxiao
     * @date 2019-07-05 09:17
     * @since v1.0
     * @version v1.0
     */
    public void addressSearchCondition(FormDataListDTO formDataListDTO) {
        List<ConditionsEntityExt> conditions = formDataListDTO.getConditions();
        AddressUtil.addressSearchCondition(conditions, formDataListDTO.getShouldConditions());
        formDataListDTO.setConditions(conditions);
    }

    /**
     * 处理下拉框
     *
     * @param formDataListDTO
     * @throws
     * @author long.rao
     * @date 2020-08-24 10:10
     */
    private void handleCondition(FormDataListDTO formDataListDTO) {
        List<ConditionsEntityExt> conditions = formDataListDTO.getConditions();
        Map<String, FieldAttrEntity> explainMap = formDataListDTO.getExplainMap();
        Integer businessType = formDataListDTO.getBusinessType();
        Iterator<ConditionsEntityExt> iterator = conditions.iterator();
        while (iterator.hasNext()){
            ConditionsEntityExt conditionsEntityExt = iterator.next();
            Integer fieldType = conditionsEntityExt.getFieldType();
            List<Object> value = conditionsEntityExt.getValue();
            String attr = conditionsEntityExt.getAttr();
            if (Objects.equals(fieldType, FieldTypeEnum.COMBO.getType()) ||
                    Objects.equals(fieldType, FieldTypeEnum.RADIO_GROUP.getType()) ||
                    Objects.equals(fieldType, FieldTypeEnum.COMBO_CHECK.getType())) {
                if (CollectionsUtil.isEmpty(value)) {
                    continue;
                }
                FieldAttrEntity fieldAttrEntity = explainMap.get(attr);
                if (Objects.nonNull(fieldAttrEntity)) {
                    List<ItemPoJo> items = fieldAttrEntity.getItems();
                    for (ItemPoJo itemPoJo : items) {
                        if (Objects.equals(itemPoJo.getIsOther(), BasicConstant.ZERO)) {
                            if (Objects.equals(itemPoJo.getText(), value.get(0))) {
                                // 因为前端回传的是text,筛选的时候需要将他转换为value值取查询
                                conditionsEntityExt.setValue(Collections.singletonList(itemPoJo.getValue()));
                                break;
                            }
                        }
                    }
                } else {
                    // 没有解释，那么是这个字段不可见，把这个筛选项去掉
                    iterator.remove();
                }
            } else if (Objects.equals(fieldType, FieldTypeEnum.LABEL.getType())) {
                FieldAttrEntity fieldAttrEntity = explainMap.get(attr);
                if (Objects.nonNull(fieldAttrEntity)) {
                    List<Object> idValue = new ArrayList<>();
                    if (CollectionsUtil.isEmpty(value)) {
                        idValue.add(-1);
                        conditionsEntityExt.setValue(idValue);
                        continue;
                    }
                    String valueStr = value.get(0).toString();
                    if (StringUtil.isEmpty(valueStr, true)) {
                        idValue.add(-1);
                        conditionsEntityExt.setValue(idValue);
                        continue;
                    }
                    List<LabelEntity> byName = labelModel.getByName(valueStr, formDataListDTO.getFormId(), formDataListDTO.getCorpid());
                    if (CollectionsUtil.isEmpty(byName)) {
                        idValue.add(-1);
                        conditionsEntityExt.setValue(idValue);
                        continue;
                    }
                    idValue.add(byName.get(0).getId());
                    conditionsEntityExt.setValue(idValue);
                } else {
                    // 没有解释，那么是这个字段不可见，把这个筛选项去掉
                    iterator.remove();
                }
            }
        }
        if (CollectionsUtil.isEmpty(conditions)) {
            // 如果没有筛选项，那么可能是字段空了，所以直接数据也要为空，兜底操作
            ConditionsEntityExt conditionsEntityExt = new ConditionsEntityExt();
            conditionsEntityExt.setAttr(FieldTypeEnum.DATAID.getAlias());
            conditionsEntityExt.setFieldType(FieldTypeEnum.DATAID.getType());
            conditionsEntityExt.setSymbol(ConditionEnum.EQUAL.getSymbol());
            conditionsEntityExt.setValue(Arrays.asList(-1L));
            conditions.add(conditionsEntityExt);
            formDataListDTO.setConditions(conditions);
        }
        formDataListDTO.setConditions(conditions);
    }

    /**
     * 处理移动端外链查询页日期展示问题
     *
     * @param paasFormDataEsListVO
     * @throws
     * @author long.rao
     * @date 2020-09-14 12:15
     */
    private void handleDateField(PaasFormDataEsListVO paasFormDataEsListVO) throws XbbException{
        List<PaasFormDataEntityExt> paasFormDataESList = paasFormDataEsListVO.getPaasFormDataESList();
        List<FieldAttrEntity> explainList = paasFormDataEsListVO.getHeadList();
        Map<String, FieldAttrEntity> fieldAttrEntityMap = BeanUtil.convertListToMap(explainList, "attr");
        for (PaasFormDataEntityExt entityExt : paasFormDataESList) {
            JSONObject data = entityExt.getData();
            Iterator<String> iterator = data.keySet().iterator();
            while (iterator.hasNext()) {
                String key = Objects.toString(iterator.next());
                FieldAttrEntity fieldAttrEntity = fieldAttrEntityMap.get(key);
                if (fieldAttrEntity == null) {
                    continue;
                }
                if (ExplainUtil.isSubForm(fieldAttrEntity.getFieldType())) {
                    JSONArray jsonArray = data.getJSONArray(key) == null ? new JSONArray() : data.getJSONArray(key);
                    JSONArray resultJsonArray = new JSONArray();
                    SubFormPoJo subForm = fieldAttrEntity.getSubForm();
                    List<? extends FieldAttrEntity> items = (subForm == null || subForm.getItems() == null) ? new ArrayList<>() : subForm.getItems();
                    Map<String, FieldAttrEntity> subExplainMap = ExplainUtil.getExplainMapByList(items);

                    for (int i = 0; i < jsonArray.size(); i++) {
                        if (!(jsonArray.get(i) instanceof Map)) {
                            continue;
                        }
                        JSONObject subJsonObject = jsonArray.getJSONObject(i);
                        Iterator subIterator = subJsonObject.keySet().iterator();
                        JSONObject subResult = new JSONObject();
                        while (subIterator.hasNext()) {
                            String subKey = Objects.toString(subIterator.next());
                            FieldAttrEntity subFieldAttrEntity = subExplainMap.get(subKey);
                            if (Objects.nonNull(subFieldAttrEntity) && Objects.equals(subFieldAttrEntity.getFieldType(), FieldTypeEnum.DATETIME.getType())) {
                                try {
                                    // 前端渲染需要正常的时间戳，但是有些时间类型的字段存的是字符串类型的时间戳，比如"1600056577",前端就不会解析，所以这边直接转一遍
                                    Long date = subJsonObject.getLong(subKey);
                                    subResult.put(subKey, date);
                                } catch (Exception e) {
                                }
                            } else {
                                subResult.put(subKey, subJsonObject.get(subKey));
                            }
                        }
                        resultJsonArray.add(subResult);
                    }
                    data.put(key, resultJsonArray);
                } else if (Objects.equals(fieldAttrEntity.getFieldType(), FieldTypeEnum.DATETIME.getType())) {
                    try {
                        // 前端渲染需要正常的时间戳，但是有些时间类型的字段存的是字符串类型的时间戳，比如"1600056577",前端就不会解析，所以这边直接转一遍
                        Long date = data.getLong(key);
                        if (Objects.equals(fieldAttrEntity.getSaasAttr(), "lastConnectTime")) {
                            Object lastConnectTime = data.get(key);
                            if (Objects.nonNull(lastConnectTime) && lastConnectTime instanceof String) {
                                data.put(key, lastConnectTime);
                                continue;
                            }
                        }
                        data.put(key, date);
                    } catch (Exception e) {
                    }
                }
            }
        }
    }

    /**
     * 过滤审批中数据
     * @param formDataListDTO 列表入参
     */
    public void filterApprovalData(FormDataListDTO formDataListDTO) {
        if(Objects.equals(XbbRefTypeEnum.PREPAYMENT_BALANCE.getCode(), formDataListDTO.getBusinessType()) || Objects.equals(formDataListDTO.getSubBusinessType(), XbbRefTypeEnum.WARNING_SEARCH.getCode())
                || Objects.equals(XbbRefTypeEnum.ORI_STOCK.getCode(), formDataListDTO.getBusinessType()) || Objects.equals(XbbRefTypeEnum.PREPAY_BALANCE.getCode(),formDataListDTO.getBusinessType())
                || Objects.equals(XbbRefTypeEnum.DISTRIBUTOR_ACCOUNT.getCode(), formDataListDTO.getBusinessType()) || Objects.equals(XbbRefTypeEnum.CUSTOMER_STATEMENT.getCode(), formDataListDTO.getBusinessType())){
            return;
        }
        boolean isDefaultApprovalGroup = Objects.equals(formDataListDTO.getDefaultGroup(), 1) && Objects.equals(formDataListDTO.getListGroupId(), Long.valueOf(ListGroupEnum.APPROVAL.getCode()));
        if (!isDefaultApprovalGroup) {
            ConditionsEntityExt conditionsEntityExt = new ConditionsEntityExt(FieldTypeEnum.FLOW_STATUS.getAlias(), "", FieldTypeEnum.FLOW_STATUS.getType(), ConditionEnum.IN.getSymbol(), Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType()));
            formDataListDTO.getConditions().add(conditionsEntityExt);
        }
    }

    @Override
    public void formatListCondition(FormDataListDTO formDataListDTO) throws XbbException{

        this.handleCondition(formDataListDTO);
        this.addressSearchCondition(formDataListDTO);
        //过滤审批中数据
        filterApprovalData(formDataListDTO);
    }



    @Override
    public FormDataUpdateGetVO get(OuterLinkBaseDTO outerLinkBaseDTO) throws XbbException {
        FormDataUpdateGetVO formDataUpdateGetVO = new FormDataUpdateGetVO();
        String token = outerLinkBaseDTO.getToken();
        OuterLinkEntity shareEntity = outerLinkModel.getByTokenAndType(token, OuterLinkTypeEnum.SHARE.getCode());
        String corpid = shareEntity.getCorpid();
        Long formId = shareEntity.getFormId();
        Integer saasMark = SaasMarkEnum.SAAS.getCode();
        Long dataId = shareEntity.getDataId();
        //校验套餐类型
        Integer feeType = packageHelp.getFeeType(corpid);
        if (Objects.equals(feeType,PackageTypeEnum.STANDARD.getType())){
            throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405014);
        }
        // 因为工作报告的总的业务类型是2101，所以不用shareEntity里的businessType，而是用具体业务的outerLink的businessType
        Integer businessType = shareEntity.getBusinessType();
        if (Objects.equals(businessType, 0)) {
            saasMark = SaasMarkEnum.PAAS.getCode();
        }
        //外链分享dataId为0
        OuterLinkEntity outerLink = outerLinkModel.getOuterLink(formId, OuterLinkTypeEnum.SHARE.getCode(), corpid, 0L);
        if (Objects.isNull(outerLink) || !Objects.equals(outerLink.getEnable(), BasicConstant.ONE)) {
            throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405003);
        }
        outerLinkBaseDTO.setDataId(dataId);
        outerLinkBaseDTO.setFormId(formId);
        outerLinkBaseDTO.setBusinessType(businessType);
        outerLinkBaseDTO.setCorpid(corpid);

        try {
            //先获取data数据
            PaasFormDataEntityExt formData = this.getFormData(dataId,corpid,businessType);
            if (Objects.equals(formData.getDel(),DelEnum.DELETE.getDel())) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100404);
            }
            // 拼富文本
            richTextService.addRichTextByDataId(dataId, corpid, formId, businessType, saasMark, DelEnum.NORMAL.getDel(), formData.getData());
            if (FlowStatusEnum.inApproval(formData.getFlowStatus()) ) {
                throw new XbbException(BuinessDefaultErrorCodeEnum.API_ERROR_200023);
            }
            // 获取表单
            PaasFormEntityExt paasFormEntityExt = this.getForm(corpid,formId,businessType);
            formDataUpdateGetVO.setPaasFormEntity(paasFormEntityExt);
            // 获取表单解释
            PaasFormExplainEntity paasFormExplainEntity = this.getFormExplain(corpid,formId,businessType);

            List<FieldAttrEntity> explainList = new ArrayList<>();
            // 获取字段解释信息，并且过滤不可见字段
            if (Objects.nonNull(paasFormExplainEntity) && StringUtil.isNotEmpty(paasFormExplainEntity.getExplains())) {
                explainList = JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);
            }
            // 处理解释
            this.handleGetExplains(explainList,outerLinkBaseDTO,formData,paasFormEntityExt);

            List<FieldAttrEntity> headList = explainList;

            Map<String, FieldAttrEntity> explainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (FieldAttrEntity fieldAttrEntity : headList) {
                fieldAttrEntity.setItems(proFormHelp.setItem(fieldAttrEntity, paasFormEntityExt));
                explainMap.put(fieldAttrEntity.getAttr(), fieldAttrEntity);
            }

            formDataUpdateGetVO.setExplainList(headList);
            // 格式化data
            this.formatData(outerLinkBaseDTO,explainMap,formData,formDataUpdateGetVO);

            // 解析数据信息
            ParseSingleRowDataDTO parseSingleRowDataDTO = new ParseSingleRowDataDTO();
            BeanUtil.copyProperties(outerLinkBaseDTO, parseSingleRowDataDTO);
            parseSingleRowDataDTO.setDataJsonObject(formData.getData());
            parseSingleRowDataDTO.setExplainMap(explainMap);
            parseSingleRowDataDTO.setOuterLink(true);
            ParseSingleRowDataVO parseSingleRowDataVO = formDataUpdateGetAnalysisDataHelp.parseSingleRowData(parseSingleRowDataDTO);
            if ( parseSingleRowDataVO == null ) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PARSE_SINGLE_ROW_DATA_FAILED);
            }

            this.handleGetData(outerLinkBaseDTO, formData,parseSingleRowDataVO,explainList);

            JSONObject newData = parseSingleRowDataVO.getResult();
            formatSpecialData(businessType, newData, outerLinkBaseDTO.getFormId(), corpid, explainMap);
            formData.setData(newData);
            formDataUpdateGetVO.setData(formData);

            this.handleGetReturnVo(formDataUpdateGetVO,outerLinkBaseDTO);

            if (Objects.equals(outerLinkBaseDTO.getPlatform(), PlatFormEnum.DINGTALK.getValue()) && Objects.equals(formDataUpdateGetVO.getHasEditPermission(), 1)) {
                if (Objects.equals(businessType, XbbRefTypeEnum.PRODUCT.getCode())) {
                    // 产品移动端没有编辑页面
                    formDataUpdateGetVO.setHasEditPermission(BasicConstant.ZERO);
                    return formDataUpdateGetVO;
                }
                // 移动端，有编辑按钮的才需要返回获取编辑的url
                String messageUrl = proBaseConfig.getPushFrontUrl() + "index.html?corpid=" + corpid + "&appid=" + Env.DING_XBB_APP_ID + "&dd_nav_bgcolor=ffff943e#";
                String updateGetUrl = "dingtalk://dingtalkclient/page/link?url=";
                messageUrl += String.format(DingtalkPageUrlEnum.UPDATE_GET.getUrl(), paasFormEntityExt.getAppId(), paasFormEntityExt.getMenuId(), paasFormEntityExt.getId(), paasFormEntityExt.getBusinessType(), saasMark, dataId);
                WorkReportTypeEnum byType = WorkReportTypeEnum.getByBusinessType(businessType);
                if (Objects.nonNull(byType)) {
                    messageUrl += "&saasSpecialParamPojo=edit";
                }
                updateGetUrl += URLEncodeUtils.encodeURL(messageUrl);
                formDataUpdateGetVO.setOuterUpdateGetUrl(updateGetUrl);
            }
        } catch (XbbException e) {
            LOG.error("outerLinkServiceImpl.get数据库查询表单数据出错", e);
            throw e;
        } catch (Exception e) {
            LOG.error("outerLinkServiceImpl.get数据库查询表单数据出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }

        return formDataUpdateGetVO;
    }

    @Override
    public void handleGetExplains(List<FieldAttrEntity> explainList,OuterLinkBaseDTO outerLinkBaseDTO,PaasFormDataEntityExt formData,PaasFormEntityExt paasFormEntityExt) throws XbbException {
        String corpid = outerLinkBaseDTO.getCorpid();
        Long formId = outerLinkBaseDTO.getFormId();
        ExplainUtil.filterSpecialAttr(explainList, OuterLinkTypeEnum.SHARE.getCode(), null);
        // 过滤各业务特殊字段
        outerLinkConfigService.removeUnsupportedAttr(outerLinkBaseDTO.getBusinessType(),explainList,OuterLinkTypeEnum.SHARE);
        OuterLinkConfigEntity permissionSetting = outerLinkConfigService.getOuterLinkConfigEntities(corpid, formId, OuterLinkTypeEnum.SHARE.getCode(), OutLinkSettingTypeEnum.PERMISSION_SETTING.getCode());
        // 外链查询处理可见可编辑
        ExplainUtil.handelFieldPermission(explainList, permissionSetting, null);
        if (CollectionsUtil.isNotEmpty(explainList)) {
            JSONObject newData = new JSONObject();
            JSONObject data = formData.getData();
            explainList.forEach(item->{
                newData.put(item.getAttr(),data.get(item.getAttr()));
            });
            formData.setData(newData);
        }

        //确认是否为创建回款单
        SheetTypeEnum sheetTypeEnum = SheetTypeEnum.getByBusinessType(outerLinkBaseDTO.getBusinessType());
        boolean sheetFlag = SheetTypeEnum.validateSheet(sheetTypeEnum);
        if (sheetFlag) {
            //如果是回/付款单、其他收入/支出单，则根据数据data内的回/付款单/其他收入/支出单类型重置sheetTypeEnum（前端传过来的businessType可能没有详细区分哪种类型回/付款单/其他收入/支出单）
            sheetTypeEnum = fundHelp.getSheetTypeEnumByData(sheetTypeEnum, formData.getData());
            fundHelp.handlePaymentSheet(false, sheetTypeEnum, explainList, corpid, paasFormEntityExt.getDistributorMark());
        }
        Integer businessType = outerLinkBaseDTO.getBusinessType();
        Integer saasMark = Objects.equals(businessType,0) ?  SaasMarkEnum.PAAS.getCode() : SaasMarkEnum.SAAS.getCode();
        if (Objects.equals(saasMark, SaasMarkEnum.SAAS.getCode())) {
            // 编辑时saas字段显示特殊逻辑
            FormatExplainDTO formatExplainDTO = new FormatExplainDTO();
            BeanUtil.copyProperties(outerLinkBaseDTO, formatExplainDTO);
            formatExplainDTO.setExplainList(explainList);
            formatExplainDTO.setDataEntity(formData);
            formatExplainDTO.setResult(formData.getData());
            formatExplainDTO.setFromCopy(false);
            formExplainHelp.formatExplain(formatExplainDTO, formData.getData());
        }
    }

    @Override
    public void formatData(OuterLinkBaseDTO outerLinkBaseDTO, Map<String, FieldAttrEntity> explainMap, PaasFormDataEntityExt formData,FormDataUpdateGetVO formDataUpdateGetVO) throws XbbException {
        JSONObject data = formData.getData();
        data.put(FieldTypeEnum.SERIALNO.getAlias(), formData.getSerialNo());
        data.put(FieldTypeEnum.ADDTIME.getAlias(), formData.getAddTime());
        data.put(FieldTypeEnum.UPDATETIME.getAlias(), formData.getUpdateTime());
    }



    @Override
    public void handleGetReturnVo(FormDataUpdateGetVO formDataUpdateGetVO,OuterLinkBaseDTO outerLinkBaseDTO) throws XbbException {
        Integer businessType = outerLinkBaseDTO.getBusinessType();
        String corpid = outerLinkBaseDTO.getCorpid();
        // 以下逻辑可以移到各自子类
        //现在前端只需要计算重复金额：重复金额为回款计划的已收款部分
        if ( Objects.equals(businessType, XbbRefTypeEnum.CONTRACT.getCode()) || Objects.equals(businessType, XbbRefTypeEnum.PURCHASE.getCode())) {
            // TODO 这个什么东西
            //Double writeOffAmount = fundMoneyHelp.getCoverCalAmount(outerLinkDTO,explainMap,businessType);
            formDataUpdateGetVO.setWriteOffAmount(0D);
        }
        if(Objects.equals(businessType, XbbRefTypeEnum.PURCHASE.getCode())){
            boolean isPurchaseProductMustBelongSupplier = Objects.equals(FormConfigEnum.PURCHASE_PRODUCT_MUST_BELONG_SUPPLIER.getConfigValue(), StringConstant.POSITIVE_NUMBER);
            //可能限制供应商
            FormConfigEntity formConfigEntity = formConfigModel.getEntityByFormId(corpid,outerLinkBaseDTO.getFormId(), FormConfigEnum.PURCHASE_PRODUCT_MUST_BELONG_SUPPLIER.getConfig());
            if (Objects.nonNull(formConfigEntity)) {
                if (Objects.equals(formConfigEntity.getConfigValue(), StringConstant.POSITIVE_NUMBER)) {
                    isPurchaseProductMustBelongSupplier = true;
                } else {
                    isPurchaseProductMustBelongSupplier = false;
                }
            }
            JSONObject saasObj = new JSONObject();
            saasObj.put("purchaseProductBelongSupplier", isPurchaseProductMustBelongSupplier);
            formDataUpdateGetVO.setSaasObj(saasObj);
        }

        if (Objects.equals(businessType, XbbRefTypeEnum.COMMUNICATE_PLAN.getCode())) {
            // 访客计划不支持编辑，所以外链分享详情页没有编辑按钮
            formDataUpdateGetVO.setHasEditPermission(BasicConstant.ZERO);
        }
    }


    /**
     * 处理特殊字段
     *
     * @param businessType
     * @param result
     * @param formId
     * @throws
     * @author long.rao
     * @date 2020-09-08 15:42
     */
    private void formatSpecialData(Integer businessType, JSONObject result, Long formId, String corpid, Map<String, FieldAttrEntity> fieldAttrEntityMap) throws XbbException{
        try {
            Iterator<String> iterator = result.keySet().iterator();
            while (iterator.hasNext()) {
                String key = Objects.toString(iterator.next());
                FieldAttrEntity fieldAttrEntity = fieldAttrEntityMap.get(key);
                if (fieldAttrEntity == null) {
                    continue;
                }
                String saasAttr = fieldAttrEntity.getSaasAttr();
                boolean rateNumFlag = Objects.equals(ContractEnum.GROSS_PROFIT_RATE.getSaasAttr(), saasAttr)
                        || Objects.equals(ContractEnum.CASH_PROFIT_RATE.getSaasAttr(), saasAttr)
                        || Objects.equals(ContractEnum.PAY_PERCENT.getSaasAttr(), saasAttr)
                        || Objects.equals(SalesOpportunityEnum.GROSS_PROFIT_RATE.getSaasAttr(), saasAttr)
                        || Objects.equals(QuotationEnum.GROSS_PROFIT_RATE.getSaasAttr(), saasAttr)
                        || Objects.equals(PurchaseEnum.RECEINE_PERCENT.getSaasAttr(), saasAttr);
                if (Objects.equals(fieldAttrEntity.getNumberType(), NumberTypeEnum.RATE.getCode())) {
                    rateNumFlag = true;
                }
                if(Objects.equals(fieldAttrEntity.getFieldType(),FieldTypeEnum.NUM.getType()) && Objects.nonNull(result.get(key))) {
                    if ( Objects.equals(businessType, XbbRefTypeEnum.PRODUCT.getCode()) && (Objects.equals(fieldAttrEntity.getAttr(),ProductEnum.COST.getAttr())||Objects.equals(fieldAttrEntity.getAttr(),ProductEnum.PRICE.getAttr()) ) ) {
                        continue;
                    }
                    // 小数精度
                    Double value;
                    try {
                        value = result.getDoubleValue(key);
                    } catch (Exception e) {
                        value = 0D;
                    }
                    if ( !rateNumFlag ) {
                        if ( Objects.equals(fieldAttrEntity.getAmountFlag(),1) ) {
                            result.put(key,attrDecimalPrecisionHelper.formatMoneyPrecision(value, fieldAttrEntity));
                        } else {
                            result.put(key,attrDecimalPrecisionHelper.setPrecision(value, fieldAttrEntity.getAccuracy()));
                        }
                    } else {
                        String decValue = attrDecimalPrecisionHelper.setDecPrecision(value * 100, fieldAttrEntity.getAccuracy());
                        result.put(key, decValue + "%");
                    }
                }
                if (ExplainUtil.isSubForm(fieldAttrEntity.getFieldType())) {
                    JSONArray jsonArray = result.getJSONArray(key) == null ? new JSONArray() : result.getJSONArray(key);
                    JSONArray resultJsonArray = new JSONArray();
                    SubFormPoJo subForm = fieldAttrEntity.getSubForm();
                    List<? extends FieldAttrEntity> items = (subForm == null || subForm.getItems() == null) ? new ArrayList<>() : subForm.getItems();
                    Map<String, FieldAttrEntity> subExplainMap = ExplainUtil.getExplainMapByList(items);

                    for (int i = 0; i < jsonArray.size(); i++) {
                        if (!(jsonArray.get(i) instanceof Map)) {
                            continue;
                        }
                        JSONObject subJsonObject = jsonArray.getJSONObject(i);
                        Iterator subIterator = subJsonObject.keySet().iterator();
                        JSONObject subResult = new JSONObject();
                        while (subIterator.hasNext()) {
                            String subKey = Objects.toString(subIterator.next());
                            FieldAttrEntity subFieldAttrEntity = subExplainMap.get(subKey);
                            if (Objects.nonNull(subFieldAttrEntity) && Objects.equals(subFieldAttrEntity.getFieldType(), FieldTypeEnum.DATETIME.getType())) {
                                try {
                                    // 前端渲染需要正常的时间戳，但是有些时间类型的字段存的是字符串类型的时间戳，比如"1600056577",前端就不会解析，所以这边直接转一遍
                                    Long date = subJsonObject.getLong(subKey);
                                    subResult.put(subKey, date);
                                } catch (Exception e) {
                                }
                            } else {
                                subResult.put(subKey, subJsonObject.get(subKey));
                            }
                        }
                        resultJsonArray.add(subResult);
                    }
                    result.put(key, resultJsonArray);
                } else if (Objects.equals(fieldAttrEntity.getFieldType(), FieldTypeEnum.DATETIME.getType())) {
                    try {
                        // 前端渲染需要正常的时间戳，但是有些时间类型的字段存的是字符串类型的时间戳，比如"1600056577",前端就不会解析，所以这边直接转一遍
                        Long date = result.getLong(key);
                        result.put(key, date);
                    } catch (Exception e) {
                    }
                }
            }
            FormConfigGetDTO formConfigGetDTO = new FormConfigGetDTO();
            formConfigGetDTO.setCorpid(corpid);
            formConfigGetDTO.setBusinessType(businessType);
            formConfigGetDTO.setFormId(formId);
            Map<String, String> lastConnectTimeMap = formDataListAnalysisDataHelp.lastConnectTime(formConfigGetDTO);
            Long lastConnectTime;
            if (Objects.equals(businessType, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode())) {
                lastConnectTime = result.getLong(CustomerManagementEnum.LAST_CONNECT_TIME.getAttr());
                String configValue = lastConnectTimeMap.get(FormConfigEnum.CUSTOMER_LAST_CONNECT_TIME.getConfig());
                if (Objects.equals(configValue, "1")) {
                    result.put(CustomerManagementEnum.LAST_CONNECT_TIME.getAttr(), DateTimeUtil.getLastConnectTimeStr(lastConnectTime));
                } else {
                    result.put(CustomerManagementEnum.LAST_CONNECT_TIME.getAttr(), DateTimeUtil.getStringEpochSecond(lastConnectTime));
                }
            } else if (Objects.equals(businessType, XbbRefTypeEnum.SALES_OPPORTUNITY.getCode())) {
                lastConnectTime = result.getLong(SalesOpportunityEnum.LAST_CONNECT_TIME.getAttr());
                String configValue = lastConnectTimeMap.get(FormConfigEnum.SALES_OPPORTUNITY_LAST_CONNECT_TIME.getConfig());
                if (Objects.equals(configValue, "1")) {
                    result.put(SalesOpportunityEnum.LAST_CONNECT_TIME.getAttr(), DateTimeUtil.getLastConnectTimeStr(lastConnectTime));
                } else {
                    result.put(SalesOpportunityEnum.LAST_CONNECT_TIME.getAttr(), DateTimeUtil.getStringEpochSecond(lastConnectTime));
                }
            } else {
                return;
            }
        } catch (Exception e) {
            LOG.error("OuterLinkServiceImpl.get.formatSpecialDate 处理特殊字段报错 businessType = " + businessType + " data为 " + result.toJSONString(), e);
        }
    }


    /**
     * 获取外链筛选项
     *
     * @param corpid
     * @param formId
     * @param headList
     * @author long.rao
     * @date 2020-08-18 09:49
     */
    private List<String> getScreens(String corpid, Long formId, List<FieldAttrEntity> headList) throws XbbException{
        OuterLinkConfigEntity outerLinkConfigEntity = null;

        Map<String,Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        params.put("type", OuterLinkTypeEnum.SEARCH.getCode());
        params.put("corpid",corpid);
        params.put("del", DelEnum.NORMAL.getDel());
        params.put("formId",formId);
        params.put("configType", OutLinkSettingTypeEnum.FILTER_SETTING.getCode());
        List<OuterLinkConfigEntity>  entityList = outerLinkConfigModel.findEntitys(params);
        if (CollectionsUtil.isNotEmpty(entityList)){
            outerLinkConfigEntity = entityList.get(0);
        }
        List<FieldAttrEntity> fields = new ArrayList<>();
        headList.forEach(item -> {
            if (FILTER_ATTR.contains(item.getFieldType())) {
                fields.add(item);
            }
        });
        List<String> screen = new ArrayList<>();
        if (Objects.isNull(outerLinkConfigEntity)){
            for (int i = 0; i < fields.size(); i++) {
                screen.add(fields.get(i).getAttr());
            }
        } else {
            List<OutLinkFieldAttrEntity> list = new ArrayList<>();
            if (StringUtil.isNotEmpty(outerLinkConfigEntity.getExplains())) {
                list = JSONArray.parseArray(outerLinkConfigEntity.getExplains(), OutLinkFieldAttrEntity.class);
            }
            list = outerLinkConfigService.syncOuterLinkField(fields,list, OuterLinkTypeEnum.SEARCH,OutLinkSettingTypeEnum.FILTER_SETTING);
            for (int i = 0; i < list.size(); i++) {
                if (Objects.equals(list.get(i).getFilterable(),1)){
                    screen.add(list.get(i).getAttr());
                }
            }
        }
        return screen;
    }


    @Override
    public FormDataAddVO add(OuterLinkAddDTO outerLinkAddDTO) throws XbbException {
        OuterLinkEntity outerLinkEntity = getTokenByType(outerLinkAddDTO.getToken(),OuterLinkTypeEnum.WRITE.getCode());
        String corpid =outerLinkEntity.getCorpid();
        Long formId = outerLinkEntity.getFormId();
        Integer businessType = outerLinkEntity.getBusinessType();
        //校验套餐类型
        Integer feeType = packageHelp.getFeeType(corpid);
        if (Objects.equals(feeType,PackageTypeEnum.STANDARD.getType())){
            throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405014);
        }
        if (Objects.equals(businessType,0) || Objects.isNull(businessType)){
            outerLinkAddDTO.setSaasMark(SaasMarkEnum.PAAS.getCode());
        } else {
            outerLinkAddDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
        }
        outerLinkAddDTO.setCorpid(corpid);
        String expandField = outerLinkEntity.getExpandField();
        String attr = outerLinkEntity.getAttr();
        // 校验高级设置
        OuterLinkConfigEntity outerLinkConfigEntity = outerLinkConfigService.getOuterLinkConfigEntities(corpid,formId, OuterLinkTypeEnum.WRITE.getCode(),OutLinkSettingTypeEnum.ADVANCED_SETTING.getCode());
        JSONObject limit =new JSONObject();
        limit.put("enable",false);
        JSONObject  openCloseTime =new JSONObject();
        openCloseTime.put("enable",false);
        if (Objects.nonNull(outerLinkConfigEntity)){
            JSONObject jsonObject = outerLinkConfigEntity.getSeniorInfo();
            if (Objects.nonNull(jsonObject)){
                limit = jsonObject.getJSONObject("limit");
                openCloseTime = jsonObject.getJSONObject("openCloseTime");
            }
        }
        // 是否在禁止提交的时间内
        Boolean forbidden = false;
        if (Objects.nonNull(openCloseTime)){
            Long startTime = openCloseTime.getLong("startTime");
            Long endTime = openCloseTime.getLong("endTime");
            Long currentTime = DateUtil.getLong();
            if(openCloseTime.getBoolean("enable")){
                if (Objects.nonNull(startTime)){
                    forbidden = currentTime <= startTime;
                }
                if (Objects.nonNull(endTime)){
                    forbidden = currentTime >= endTime;
                }
            }
            if(forbidden){
                throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405001);
            }
        }
        // 限制提交量
        limitAdvanced(outerLinkAddDTO.getSaasMark(),corpid, formId, businessType, limit);

        // 外链数据加上拓展字段
        outerLinkAddDTO.getDataList().put(attr,expandField);

        FormDataAddVO formDataSaveVO = new FormDataAddVO();
        Integer oneStatus = packageStatusHelp.getPackageStatus(corpid, ValueAddedTypeEnum.ONE_FORM_DATA_NUM, 1);
        Integer allStatus = packageStatusHelp.getPackageStatus(corpid, ValueAddedTypeEnum.TOTAL_FORM_DATA_NUM, 1);
        if ( !Objects.equals(oneStatus, PackageStatusEnum.NORMAL.getCode()) && !Objects.equals(oneStatus, PackageStatusEnum.WARNING.getCode()) ) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100074, I18nStringConstant.SINGLE_TABLE_NUM_LIMIT);
        }

        if ( !Objects.equals(allStatus, PackageStatusEnum.NORMAL.getCode()) && !Objects.equals(allStatus, PackageStatusEnum.WARNING.getCode()) ) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100074, I18nStringConstant.TOTAL_TABLE_NUM_LIMIT);
        }
        //工单逻辑与其他业务逻辑分离，在workOrderFormDataService.add中已加异常后的es删除相关数据操作 TODO 待处理
        if ( outerLinkAddDTO.getBusinessType() ==  XbbRefTypeEnum.WORK_ORDER.getCode() ) {
            this.addForWorkOrder(outerLinkAddDTO,formDataSaveVO);
            return formDataSaveVO;
        }

        try {
            PaasFormEntityExt paasFormEntityExt;
            // 工作报告从首页快捷新建获取的formId不正确，需要重新再获取下
            if (Objects.equals(businessType, XbbRefTypeEnum.WORK_REPORT.getCode())) {
                paasFormEntityExt = paasFormModel.getByBusinessType(outerLinkAddDTO.getSubBusinessType(),corpid);
            } else {
                paasFormEntityExt = paasFormModel.getByKey(outerLinkAddDTO.getFormId(), outerLinkAddDTO.getCorpid());
            }
            if ( paasFormEntityExt == null ) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
            }
            outerLinkAddDTO.setFormId(paasFormEntityExt.getId());
            PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByFormId(outerLinkAddDTO.getFormId(), corpid);
            if ( Objects.isNull(paasFormExplainEntity) ) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
            }
            JSONObject data = outerLinkAddDTO.getDataList();


            Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(paasFormExplainEntity.getExplains(), null);

            ValidateDataDTO validateDataDTO = new ValidateDataDTO();
            BeanUtil.copyProperties(outerLinkAddDTO, validateDataDTO);
            validateDataDTO.setData(data);
            validateDataDTO.setExplainMap(explainMap);
            //销项发票、进项发票、回款单、付款单金额明细处理
            SheetTypeEnum sheetTypeEnum = SheetTypeEnum.getByBusinessType(businessType);
            JSONArray amountDetail = saasSaveHelper.getAmountDetail4Check(null, sheetTypeEnum, data,businessType);
            outerLinkAddDTO.setAmountDetail(amountDetail);
            validateDataDTO.setAmountDetail(amountDetail);
            ProSaveHelp.analyticalData(validateDataDTO);

            validateDataDTO.setFromOuterLink(BasicConstant.ONE);
            validateDataDTO.setIsNew(true);
            this.beforeSave(validateDataDTO);

            if ( validateDataDTO.getSubBusinessType() != null ) {
                outerLinkAddDTO.setSubBusinessType(validateDataDTO.getSubBusinessType());
            }

            if ( CollectionsUtil.isNotEmpty(amountDetail) ) {
                SaasNeedRedundantAttrPojo saasNeedRedundantAttrPoJo = validateDataDTO.getSaasNeedRedundantAttrPoJo();
                saasNeedRedundantAttrPoJo.setAmountDetail(amountDetail);
            }
            outerLinkAddDTO.setSaasNeedRedundantAttrPoJo(validateDataDTO.getSaasNeedRedundantAttrPoJo());
            PaasFormDataEntity paasFormDataEntity = new PaasFormDataEntity();
            BeanUtil.copyProperties(outerLinkAddDTO, paasFormDataEntity);
            paasFormDataEntity.setOwnerId(PaasConstant.OUT_LINK_USER_ID);

            if ( Objects.nonNull(outerLinkAddDTO.getOwnerId()) && !outerLinkAddDTO.getOwnerId().isEmpty() ) {
                paasFormDataEntity.setOwnerId(Objects.toString(outerLinkAddDTO.getOwnerId().get(0).getId(), ""));
            }
            String serialNo = outerLinkAddDTO.getSerialNo();
            FieldAttrEntity fieldAttrEntity = explainMap.get(FieldTypeEnum.SERIALNO.getAlias());
            if (Objects.nonNull(fieldAttrEntity) && Objects.equals(fieldAttrEntity.getStrictController(), BasicConstant.ONE)){
                serialNo = serialNoService.getSerialNo(corpid, formId, fieldAttrEntity);
            }
            paasFormDataEntity.setData(outerLinkAddDTO.getDataList());
            paasFormDataEntity.setSerialNo(serialNo);

            paasFormDataEntity.setMenuId(paasFormEntityExt.getMenuId());
            paasFormDataEntity.setFlowStatus(FlowStatusEnum.NOT_NEED_APPROVAL.getType());
            paasFormDataEntity.setCreatorId(PaasConstant.OUT_LINK_USER_ID);

            outerLinkAddDTO.setExplainMap(explainMap);
            FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
            BeanUtil.copyProperties(outerLinkAddDTO,formDataAddDTO);
            formDataAddDTO.setFromOuterLink(BasicConstant.ONE);
            AfterSaveVO afterSaveVO = this.insert(formDataAddDTO, paasFormDataEntity, paasFormEntityExt);
            formDataSaveVO.setDataId(afterSaveVO.getFormDataId());
            String businessRules = paasFormEntityExt.getBusinessRules();
            if (!Objects.equals(1, outerLinkAddDTO.getIsBusinessRule()) && Objects.equals("1", businessRules)) {
                ActiveRuleDTO activeRuleDTO = new ActiveRuleDTO();
                BeanUtil.copyProperties(outerLinkAddDTO, activeRuleDTO);
                activeRuleDTO.setDataId(paasFormDataEntity.getId());
                long now = DateUtil.getInt();
                paasFormDataEntity.setAddTime(now);
                paasFormDataEntity.setUpdateTime(now);
                activeRuleDTO.setPaasFormDataEntity(paasFormDataEntity);
                activeRuleDTO.setExplainList(JSON.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class));
            }
            if ( Objects.equals(afterSaveVO.getCode(), PaasConstant.FORM_ADD_PROCESS_RETURN_CODE) ) {
                formDataSaveVO.setMsg(afterSaveVO.getMsg());
                formDataSaveVO.setCode(afterSaveVO.getCode());
            } else {
                formDataSaveVO.setMsg(I18nMessageUtil.getMessage(MessageConstant.FORM_ADD_RETURN_MSG));
                formDataSaveVO.setCode(PaasConstant.FORM_ADD_RETURN_CODE);
            }
            formDataSaveVO.setFormDataId(paasFormDataEntity.getId());

            // 更新缓存数据
            // 开启不开启限制 数据量都要计入
            String[] keys = getKeys(corpid,formId);
            for (int i = 0; i < keys.length; i++) {
                String key = keys[i];
                String value = paasRedisHelper.getValue(RedisPrefixConstant.OUT_LINK_ADVANCED, key);
                if (Objects.nonNull(value)){
                    long valueLong = Long.parseLong(value);
                    valueLong ++;
                    paasRedisHelper.removeValue(RedisPrefixConstant.OUT_LINK_ADVANCED, key);
                    paasRedisHelper.setValue(RedisPrefixConstant.OUT_LINK_ADVANCED, key,valueLong, RedisConstant.SHORT_DURATION);
                } else {
                    Integer startTime = null;
                    Integer endTime = null;
                    if (Objects.equals(i, 0)) {
                    } else if (Objects.equals(i, 1)) {
                        startTime = DateUtil.getTodayInt();
                        endTime = DateUtil.getTodayInt() + TimeConstant.SECONDS_PER_DAY;
                    } else if (Objects.equals(i, 2)) {
                        startTime = DateUtil.getFirstDateOfThisMonth();
                        endTime = DateUtil.getFirstDateOfThisMonth() + TimeConstant.SECONDS_PER_MONTH;
                    } else if (Objects.equals(i, 3)) {
                        startTime = DateUtil.getFirstDateOfYear();
                        endTime = DateUtil.getFirstDateOfYear() + TimeConstant.SECONDS_PER_YEAR;
                    }
                    BoolQueryBuilder boolQueryBuilder = boolQuery();
                    boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
                    boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
                    boolQueryBuilder.filter(termQuery("formId", formId));
                    boolQueryBuilder.filter(termQuery("creatorId.keyword", -3));
                    if (Objects.nonNull(startTime) && Objects.nonNull(endTime)) {
                        boolQueryBuilder.filter(rangeQuery("addTime").gte(startTime).lt(endTime));
                    }
                    IndexTypeEnum indexTypeEnum = indexTypeModel.getIndexType(corpid, businessType, outerLinkAddDTO.getSaasMark());

                    ElasticAggsPojo elasticAggsPojo = esHelper.elasticAggs(indexTypeEnum, boolQueryBuilder, null);
                    long valueLong = Long.parseLong(elasticAggsPojo.getTotal());
                    valueLong ++;
                    paasRedisHelper.setValue(RedisPrefixConstant.OUT_LINK_ADVANCED, key,valueLong, RedisConstant.SHORT_DURATION);
                }
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("paasFormData数据库保存表单数据出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return formDataSaveVO;

    }

    /**
     * 高级筛选限制提交量
     * @param corpid
     * @param formId
     * @param businessType
     * @param limit
     * @throws XbbException
     */
    public void limitAdvanced(Integer saasMark,String corpid, Long formId, Integer businessType, JSONObject limit) throws XbbException {
        if (Objects.nonNull(limit)) {
            if (limit.getBoolean("enable")) {
                Integer type = limit.getInteger("type");
                Integer count = limit.getInteger("count");
                String key = null;
                // 对于不同的type，key的生成规则不一样
                if (Objects.equals(type,OutLinkAdvancedEnum.TOTAL.getCode())){
                    key = OutLinkAdvancedEnum.TOTAL.getCode() + corpid + formId;
                } else if (Objects.equals(type,OutLinkAdvancedEnum.DAY.getCode())){
                    key = OutLinkAdvancedEnum.DAY.getCode() + DateUtil.getDateString(DateUtil.getInt()) + corpid + formId;
                } else if (Objects.equals(type,OutLinkAdvancedEnum.MONTH.getCode())){
                    key = OutLinkAdvancedEnum.MONTH.getCode() + DateUtil.getString(new SimpleDateFormat("yyyy-MM")) + corpid + formId;
                } else if (Objects.equals(type,OutLinkAdvancedEnum.YEAR.getCode())){
                    key = OutLinkAdvancedEnum.YEAR.getCode() + DateUtil.getNowSDFYears() + corpid + formId;
                }
                String value = paasRedisHelper.getValue(RedisPrefixConstant.OUT_LINK_ADVANCED, key);
                if (Objects.nonNull(value)) {
                    // 缓存中能拿到数据
                    long valueLong = Long.parseLong(value);
                    if (++valueLong > count) {
                        throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405002);
                    }
                } else {
                    // 缓存中拿不到数据，从db汇总
                    Integer startTime = null;
                    Integer endTime = null;
                    if (Objects.equals(type, OutLinkAdvancedEnum.TOTAL.getCode())) {
                    } else if (Objects.equals(type, OutLinkAdvancedEnum.DAY.getCode())) {
                        startTime = DateUtil.getTodayInt();
                        endTime = DateUtil.getTodayInt() + TimeConstant.SECONDS_PER_DAY;
                    } else if (Objects.equals(type, OutLinkAdvancedEnum.MONTH.getCode())) {
                        startTime = DateUtil.getFirstDateOfThisMonth();
                        endTime = DateUtil.getFirstDateOfThisMonth() + TimeConstant.SECONDS_PER_MONTH;
                    } else if (Objects.equals(type, OutLinkAdvancedEnum.YEAR.getCode())) {
                        startTime = DateUtil.getFirstDateOfYear();
                        endTime = DateUtil.getFirstDateOfYear() + TimeConstant.SECONDS_PER_YEAR;
                    }
                    BoolQueryBuilder boolQueryBuilder = boolQuery();
                    boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
                    boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
                    boolQueryBuilder.filter(termQuery("formId", formId));
                    boolQueryBuilder.filter(termQuery("creatorId.keyword", -3));
                    if (Objects.nonNull(startTime) && Objects.nonNull(endTime)) {
                        boolQueryBuilder.filter(rangeQuery("addTime").gte(startTime).lt(endTime));
                    }
                    IndexTypeEnum indexTypeEnum = indexTypeModel.getIndexType(corpid, businessType, saasMark);

                    ElasticAggsPojo elasticAggsPojo = esHelper.elasticAggs(indexTypeEnum, boolQueryBuilder, null);
                    long valueLong = Long.parseLong(elasticAggsPojo.getTotal());
                    if (++valueLong > count) {
                        throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405002);
                    }
                }
            }
        }
    }

    /**
     * 获取高级设置对应key
     * @param
     * @param corpid
     * @param formId
     * @return
     */
    private String[] getKeys(String corpid,Long formId){
        String[] keyArray = new String[4];
        keyArray[0] = OutLinkAdvancedEnum.TOTAL.getCode() + corpid + formId;
        keyArray[1] = OutLinkAdvancedEnum.DAY.getCode() + DateUtil.getDateString(DateUtil.getInt()) + corpid + formId;
        keyArray[2] = OutLinkAdvancedEnum.MONTH.getCode() + DateUtil.getString(new SimpleDateFormat("yyyy-MM")) + corpid + formId;
        keyArray[3] = OutLinkAdvancedEnum.YEAR.getCode() + DateUtil.getNowSDFYears() + corpid + formId;
        return keyArray;
    }

    @Override
    public FormDataAddGetVO addGet(OuterLinkAddGetDTO outerLinkAddGetDTO) throws XbbException {
        OuterLinkEntity outerLinkEntity = getTokenByType(outerLinkAddGetDTO.getToken(),OuterLinkTypeEnum.WRITE.getCode());
        String corpid =outerLinkEntity.getCorpid();
        Long formId = outerLinkEntity.getFormId();
        Integer businessType = outerLinkEntity.getBusinessType();
        outerLinkAddGetDTO.setCorpid(corpid);
        //校验套餐类型
        Integer feeType = packageHelp.getFeeType(corpid);
        if (Objects.equals(feeType,PackageTypeEnum.STANDARD.getType())){
            throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405014);
        }
        if (Objects.equals(businessType,0) || Objects.isNull(businessType)){
            outerLinkAddGetDTO.setSaasMark(SaasMarkEnum.PAAS.getCode());
        } else {
            outerLinkAddGetDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
        }
        FormDataAddGetVO formDataAddGetVO = new FormDataAddGetVO();

        if (!Objects.equals(outerLinkAddGetDTO.getOuterShow(), BasicConstant.ONE)) {
            // 从外观设置这里获取addGet接口不需要校验高级设置
            // 校验高级设置
            OuterLinkConfigEntity outerLinkConfig = outerLinkConfigService.getOuterLinkConfigEntities(corpid, formId, OuterLinkTypeEnum.WRITE.getCode(), OutLinkSettingTypeEnum.ADVANCED_SETTING.getCode());
            JSONObject limit = new JSONObject();
            limit.put("enable", false);
            JSONObject openCloseTime = new JSONObject();
            openCloseTime.put("enable", false);
            if (Objects.nonNull(outerLinkConfig)) {
                JSONObject jsonObject = outerLinkConfig.getSeniorInfo();
                if (Objects.nonNull(jsonObject)) {
                    limit = jsonObject.getJSONObject("limit");
                    openCloseTime = jsonObject.getJSONObject("openCloseTime");
                }
            }
            // 是否在禁止提交的时间内
            Boolean forbidden = false;
            if (Objects.nonNull(openCloseTime)) {
                Long startTime = openCloseTime.getLong("startTime");
                Long endTime = openCloseTime.getLong("endTime");
                Long currentTime = DateUtil.getLong();
                if (openCloseTime.getBoolean("enable")) {
                    if (Objects.nonNull(startTime)) {
                        forbidden = currentTime <= startTime;
                    }
                    if (Objects.nonNull(endTime)) {
                        forbidden = currentTime >= endTime;
                    }
                }
                if (forbidden) {
                    throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405001);
                }
            }
            // 限制提交量
            limitAdvanced(outerLinkAddGetDTO.getSaasMark(), corpid, formId, businessType, limit);
        }

        try {
            // TODO 待处理
            if ( Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), businessType) ) {
                formDataAddGetVO  = this.addGetForWorkOrder(outerLinkAddGetDTO,formDataAddGetVO);
                return formDataAddGetVO;
            }
            PaasFormEntityExt paasFormEntityExt = paasFormModel.getByKey(formId, corpid);
            if ( Objects.isNull(paasFormEntityExt) ) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018, MessageConstant.FORM_NOT_EXIST);
            }
            FormUtil.handleFormEntity(paasFormEntityExt, 1, businessType);
            formDataAddGetVO.setPaasFormEntity(paasFormEntityExt);
            PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByFormId(formId, corpid);
            if ( Objects.isNull(paasFormExplainEntity) ) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
            }
            // 获取字段解释信息，根据权限设置过滤不可见字段 start
            List<FieldAttrEntity> explainList = JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);
            ExplainUtil.filterSpecialAttr(explainList, OuterLinkTypeEnum.WRITE.getCode(), null);
            // 过滤各业务特殊字段
            outerLinkConfigService.removeUnsupportedAttr(businessType,explainList,OuterLinkTypeEnum.WRITE);

            explainList.forEach(item -> {
                item.setVisible(1);
                item.setEditable(1);
                item.setVisibleScopeEnable(0);
                item.setEditableAdvanceEnable(0);
                if (ExplainUtil.isSubFormNoSelectProduct(item.getFieldType())){
                    List<? extends FieldAttrEntity> subExplainList = item.getSubForm().getItems();
                    for (FieldAttrEntity subAttrEntity : subExplainList) {
                        subAttrEntity.setVisible(1);
                        subAttrEntity.setEditable(1);
                        subAttrEntity.setVisibleScopeEnable(0);
                        subAttrEntity.setEditableAdvanceEnable(0);
                    }
                    item.getSubForm().setItems(subExplainList);
                }
                // 阶段比例设置为不可编辑，小数位数为0位
                if(Objects.equals(item.getFieldType(),FieldTypeEnum.STAGE_RATIO.getType())){
                    item.setEditable(0);
                    item.setAccuracy(0);
                }
            });
            HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();
            BeanUtil.copyProperties(outerLinkAddGetDTO, handlerExplainDTO, false);
            handlerExplainDTO.setExplainList(explainList);
            handlerExplainDTO.setPaasFormEntityExt(paasFormEntityExt);
            handlerExplainDTO.setIsOuterLink(BasicConstant.ONE);
            HandlerExplainVO handlerExplainVO = formDataAddFormExplainHandlerName.handleExplain(handlerExplainDTO);
            if ( handlerExplainVO == null ) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_NOT_EXIST);
            }
            explainList = handlerExplainVO.getHeadList();
            OuterLinkConfigEntity outerLinkConfigEntity = outerLinkConfigService.getOuterLinkConfigEntities(corpid,formId,OuterLinkTypeEnum.WRITE.getCode(),OutLinkSettingTypeEnum.PERMISSION_SETTING.getCode());
            List<String> notVisableAttr = new ArrayList<>();
            List<String> notEditableAttr = new ArrayList<>();
            Map<String,List<String>> notVisiableSubAttrMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<String,List<String>> notEditableSubAttrMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if (Objects.nonNull(outerLinkConfigEntity)){
                String explains = outerLinkConfigEntity.getExplains();
                List<OutLinkFieldAttrEntity> outLinkFieldAttrEntities = JSONArray.parseArray(explains,OutLinkFieldAttrEntity.class);
                for (int i = 0; i < outLinkFieldAttrEntities.size(); i++) {
                    OutLinkFieldAttrEntity entity = outLinkFieldAttrEntities.get(i);
                    //  子表单内不可见字段
                    List<String> notVisiableSubAttrList = new ArrayList<>();
                    List<String> notEditableSubAttrList = new ArrayList<>();
                    if (ExplainUtil.isSubFormNoSelectProduct(entity.getFieldType())){
                        List<OutLinkFieldAttrEntity> subExplainList = JSONObject.parseArray(JSON.toJSONString(entity.getSubForm().getItems()), OutLinkFieldAttrEntity.class);
                        subExplainList.forEach(item -> {
                            if (!Objects.equals(item.getVisible(),1)){
                                notVisiableSubAttrList.add(item.getAttr());
                            }
                            if (!Objects.equals(item.getEditable(),1)){
                                notEditableSubAttrList.add(item.getAttr());
                            }
                        });
                        notVisiableSubAttrMap.put(entity.getAttr(),notVisiableSubAttrList);
                        notEditableSubAttrMap.put(entity.getAttr(),notEditableSubAttrList);
                    }
                    if (!Objects.equals(entity.getVisible(),1)){
                        notVisableAttr.add(entity.getAttr());
                    }
                    if (!Objects.equals(entity.getEditable(),1)){
                        notEditableAttr.add(entity.getAttr());
                    }
                }
            }
            Iterator it = explainList.iterator();
            while (it.hasNext()){
                FieldAttrEntity fieldAttrEntity = (FieldAttrEntity) it.next();
                if (notVisableAttr.contains(fieldAttrEntity.getAttr())){
                    // 字段不可见 将可见状态赋值为0，用于公式计算
                    fieldAttrEntity.setVisible(0);
                    continue;
                }
                if (notEditableAttr.contains(fieldAttrEntity.getAttr())){
                    fieldAttrEntity.setEditable(0);
                }
                if (ExplainUtil.isSubFormNoSelectProduct(fieldAttrEntity.getFieldType())){
                    List<? extends FieldAttrEntity> subExplainList = fieldAttrEntity.getSubForm().getItems();
                    List<String> notVisiableSubAttrList = notVisiableSubAttrMap.getOrDefault(fieldAttrEntity.getAttr(),new ArrayList<>());
                    if (Objects.equals(fieldAttrEntity.getSaasAttr(), CustomerManagementEnum.PHONE.getSaasAttr())) {
                        // 外链填写，如果电话字段不可见，不能romve，而是设置visiable为o，否则前端显示有问题
                        subExplainList.forEach(item -> {
                            if (notVisiableSubAttrList.contains(item.getAttr())){
                                item.setVisible(0);
                            }
                        });
                    } else {
                        subExplainList.forEach(item->{
                            if ( notVisiableSubAttrList.contains(item.getAttr())) {
                                item.setVisible(0);
                            }
                        });
                    }
                    List<String> notEditableSubList = notEditableSubAttrMap.getOrDefault(fieldAttrEntity.getAttr(),new ArrayList<>());
                    subExplainList.forEach(item -> {
                        if (notEditableSubList.contains(item.getAttr())){
                            item.setEditable(0);
                        }
                    });
                    fieldAttrEntity.getSubForm().setItems(subExplainList);
                }
            }
            // 显示设置 替换attrName
            Map<String,String> namedMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<String,String> namedSubMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            OuterLinkConfigEntity configEntity = outerLinkConfigService.getOuterLinkConfigEntities(corpid,formId,OuterLinkTypeEnum.WRITE.getCode(),OutLinkSettingTypeEnum.DISPLAY_SETTING.getCode());
            if (Objects.nonNull(configEntity)){
                String explains = configEntity.getExplains();
                List<OutLinkFieldAttrEntity> outLinkFieldAttrEntities = JSONArray.parseArray(explains,OutLinkFieldAttrEntity.class);
                for (int i = 0; i < outLinkFieldAttrEntities.size(); i++) {
                    OutLinkFieldAttrEntity entity = outLinkFieldAttrEntities.get(i);
                    if (ExplainUtil.isSubFormNoSelectProduct(entity.getFieldType())){
                        List<? extends OutLinkFieldAttrEntity> subExplainList = entity.getSubForm().getItems();
                        if (Objects.nonNull(subExplainList)){
                            for (int j = 0; j < subExplainList.size(); j++) {
                                OutLinkFieldAttrEntity value = subExplainList.get(j);
                                if (Objects.equals(value.getRenamed(),1)){
                                    namedSubMap.put(entity.getAttr() + "." + value.getAttr(),value.getDefaultName());
                                }
                            }
                        }
                    }
                    if (Objects.equals(entity.getRenamed(),1)){
                        namedMap.put(entity.getAttr(),entity.getDefaultName());
                    }
                }
                if (StringUtil.isNotEmpty(configEntity.getDefaultFormName()) ){
                    paasFormEntityExt.setName(configEntity.getDefaultFormName());
                }
            }
            for (int i = 0; i < explainList.size(); i++) {
                FieldAttrEntity fieldAttrEntity = explainList.get(i);
                if (ExplainUtil.isSubFormNoSelectProduct(fieldAttrEntity.getFieldType())){
                    List<? extends FieldAttrEntity> subExplainList = fieldAttrEntity.getSubForm().getItems();
                    if (Objects.nonNull(subExplainList)){
                        for (int j = 0; j < subExplainList.size(); j++) {
                            FieldAttrEntity fieldAttr = subExplainList.get(j);
                            if (namedSubMap.containsKey(fieldAttrEntity.getAttr() + "." + fieldAttr.getAttr())){
                                fieldAttr.setAttrName(namedSubMap.getOrDefault(fieldAttrEntity.getAttr() + "." + fieldAttr.getAttr(),""));
                            }
                        }
                    }
                    fieldAttrEntity.getSubForm().setItems(subExplainList);
                }
                if (namedMap.containsKey(fieldAttrEntity.getAttr())){
                    fieldAttrEntity.setAttrName(namedMap.getOrDefault(fieldAttrEntity.getAttr(),""));
                }
            }

            // 查询客户名称和电话判重设置
            if ( Objects.equals(businessType, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode()) ) {
                handlerCustomerRepeat(corpid, formId, explainList);
            }
            String serialNo = "";
            if (!Objects.equals(outerLinkAddGetDTO.getOuterShow(), BasicConstant.ONE)) {
                // 外观设置请求该接口不对流水号做处理，防止跳号
                for (FieldAttrEntity fieldAttrEntity : explainList) {
                    // 获取流水号
                    if (Objects.equals(fieldAttrEntity.getAttr(), FieldTypeEnum.SERIALNO.getAlias()) && Objects.equals(fieldAttrEntity.getStrictController(), BasicConstant.ZERO)) {
                        serialNo = serialNoService.getSerialNo(corpid, formId, fieldAttrEntity);
                    }
                    // fix:18442 【移动端、web端】新建、编辑页面，不展示系统自动生成字段
                    if (Objects.equals(fieldAttrEntity.getUnableEditMemo(), I18nMessageUtil.getMessage(StringConstant.AUTO_GEN_FIELD))) {
                        fieldAttrEntity.setVisible(0);
                    }
                }
                if (Objects.equals(businessType, XbbRefTypeEnum.QUOTATION.getCode())) {
                    // 报价单编号是组号加版本号
                    formDataAddGetVO.setGroupNumber(serialNo);
                    serialNo = serialNo + StringConstant.DEFAULT_VERSION;
                }
            }
            formDataAddGetVO.setSerialNo(serialNo);

            // 获取字段解释信息，并且过滤不可见字段 end
            // 新建表单时SaaS某些字段赋初始值
            if ( Objects.equals(1, SaasMarkEnum.SAAS.getCode()) ) {

                FormatExplainDTO formatExplainDTO = new FormatExplainDTO();
                BeanUtil.copyProperties(outerLinkAddGetDTO, formatExplainDTO);
                formatExplainDTO.setExplainList(explainList);

                //saasAddHelp.formatExplain(formatExplainDTO);
                formDataAddGetVO.setExplainList(formatExplainDTO.getExplainList());
                // saas特殊返回字段，放在一个对象中
                //saasAddHelp.formatSaasAttrToReturn(formDataAddGetVO, outerLinkAddGetDTO);
                explainList = formDataAddGetVO.getExplainList();
            }
            formDataAddGetVO.setExplainList(explainList);
            OuterLinkAppearanceGetDTO outerLinkAppearanceGetDTO = new OuterLinkAppearanceGetDTO();
            outerLinkAppearanceGetDTO.setCorpid(corpid);
            outerLinkAppearanceGetDTO.setFormId(formId);
            OuterLinkAppearanceGetVO appearance = outerLinkConfigService.getAppearance(outerLinkAppearanceGetDTO);
            JSONObject appearanceObj = new JSONObject();
            appearanceObj.put("themeList", appearance.getThemeList());
            appearanceObj.put("configInfo", appearance.getConfigInfo());
            appearanceObj.put("initFlag", appearance.getInitFlag());
            formDataAddGetVO.setOuterLinkAppearance(appearanceObj);
            String value = formConfigModel.getConfigValueByRedis(RedisPrefixConstant.ASSIGNMENT_RULES, corpid, formId, paasFormEntityExt.getSaasMark(), paasFormEntityExt.getBusinessType(), "0");
            if (StringUtil.isNotEmpty(value)) {
                formDataAddGetVO.setAssignmentRules(Integer.valueOf(value));
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("paasFormData数据库查询表单数据出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return formDataAddGetVO;
    }

    /**
     *
     * @param corpid
     * @param formId
     * @param explainList
     */
    private void handlerCustomerRepeat(String corpid, Long formId, List<FieldAttrEntity> explainList) {
        String nameRepeat = FormConfigEnum.CUSTOMER_NAME_REPEAT_TYPE.getConfig();
        String phoneRepeat = FormConfigEnum.CUSTOMER_PHONE_REPEAT_TYPE.getConfig();
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("corpid", corpid);
        param.put("formId", formId);
        param.put("configIn", Arrays.asList(nameRepeat, phoneRepeat));
        param.put("del", DelEnum.NORMAL.getDel());
        List<FormConfigEntity> formConfigEntityList = formConfigModel.findEntitys(param);
        Map<String, String> formConfigMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for ( FormConfigEntity configEntity : formConfigEntityList ) {
            formConfigMap.put(configEntity.getConfig(), configEntity.getConfigValue());
        }

        if ( Objects.nonNull(formConfigMap.get(nameRepeat)) ) {
            for ( FieldAttrEntity fieldAttrEntity : explainList ) {
                if ( Objects.equals(fieldAttrEntity.getAttr(), CustomerManagementEnum.NAME.getAttr()) ) {
                    // 根据表单配置更改 noRepeat 的值(不启用时noRepeat为0，模板内和全局时noRepeat为1)
                    if ( Objects.equals(formConfigMap.get(nameRepeat), RepeatTypeEnum.REPEAT_CANCEL.getType().toString()) ) {
                        fieldAttrEntity.setNoRepeat(RepeatTypeEnum.REPEAT_CANCEL.getType());
                    } else {
                        fieldAttrEntity.setNoRepeat(RepeatTypeEnum.REPEAT_SINGLE.getType());
                    }
                    break;
                }
            }
        }

        if ( Objects.nonNull(formConfigMap.get(phoneRepeat)) ) {
            for ( FieldAttrEntity fieldAttrEntity : explainList ) {
                if ( Objects.equals(fieldAttrEntity.getAttr(), CustomerManagementEnum.PHONE.getAttr()) ) {
                    List<? extends FieldAttrEntity> items = fieldAttrEntity.getSubForm().getItems();
                    for ( FieldAttrEntity item : items ) {
                        if ( Objects.equals(item.getAttr(), "text_2") ) {
                            // 根据表单配置更改 noRepeat 的值(不启用时noRepeat为0，模板内和全局时noRepeat为1)
                            if ( Objects.equals(formConfigMap.get(phoneRepeat), RepeatTypeEnum.REPEAT_CANCEL.getType().toString()) ) {
                                item.setNoRepeat(RepeatTypeEnum.REPEAT_CANCEL.getType());
                            } else {
                                item.setNoRepeat(RepeatTypeEnum.REPEAT_SINGLE.getType());
                            }
                        }
                    }
                    break;
                }
            }
        }
    }


    /**
     * 校验并解析token 解析出businessType corpid formId expandField
     * @param
     * @param token
     * @param
     * @throws XbbException
     */
    @Override
    public OuterLinkEntity getTokenByType(String token,Integer type) throws XbbException{
        Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        params.put("hashCode", token);
        params.put("del", 0);
//        params.put("enable",1);
        params.put("type",type);
        List<OuterLinkEntity> outerLinkEntityList = outerLinkModel.findEntitys(params);
        if (CollectionsUtil.isEmpty(outerLinkEntityList)){
            throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405006);
        }
//        // 外链填写有拓展链接 外面关闭 里面的链接也应失效
        if (Objects.equals(type,OuterLinkTypeEnum.WRITE.getCode())) {
            for (int i = 0; i < outerLinkEntityList.size(); i++) {
                OuterLinkEntity outerLinkEntity = outerLinkEntityList.get(i);
                if (Objects.nonNull(outerLinkEntity.getAttr()) || Objects.nonNull(outerLinkEntity.getExpandField())) {
                    Integer businessType = outerLinkEntity.getBusinessType();
                    Long formId = outerLinkEntity.getFormId();
                    String corpid = outerLinkEntity.getCorpid();
                    params.clear();
                    params.put("businessType", businessType);
                    params.put("del", 0);
                    params.put("formId", formId);
                    params.put("corpid", corpid);
                    params.put("type", OuterLinkTypeEnum.WRITE.getCode());
                    params.put("excludeExpandField", "excludeExpandField");
                    List<OuterLinkEntity> outerLinkEntityLists = outerLinkModel.findEntitys(params);
                    if (Objects.nonNull(outerLinkEntityLists)) {
                        if (Objects.equals(outerLinkEntityLists.get(0).getEnable(), 0)) {
                            throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405010);
                        }
                    }
                    return outerLinkEntity;
                }
            }
        }
        if (Objects.equals(outerLinkEntityList.get(0).getEnable(),0)){
            throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405010);
        }
        return outerLinkEntityList.get(0);
    }

    /**
     * 外链筛选仅支持单行文本、单选按钮、下拉框、地址、流水号、数字、日期、标签
     * 其中，数字和日期都是范围筛选，其它都是等于
     *
     * @author long.rao
     * @date 2020-08-20 17:21
     */
    private Map<String, List<ConditionClass>> getConditionList() {
        Map<String, List<ConditionClass>> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        ConditionClass equalCondition = new ConditionClass();
        equalCondition.setSymbol(ConditionEnum.EQUAL.getSymbol());
        equalCondition.setReplaceSymbol(ConditionEnum.EQUAL.getReplaceSymbol());
        equalCondition.setMemo(ConditionEnum.EQUAL.getMemo());

        ConditionClass rangeCondition = new ConditionClass();
        rangeCondition.setSymbol(ConditionEnum.RANGE.getSymbol());
        rangeCondition.setReplaceSymbol(ConditionEnum.RANGE.getReplaceSymbol());
        rangeCondition.setMemo(ConditionEnum.RANGE.getMemo());
        map.put(FieldTypeEnum.TEXT.getType().toString(), Arrays.asList(equalCondition));
        map.put(FieldTypeEnum.RADIO_GROUP.getType().toString(), Arrays.asList(equalCondition));
        map.put(FieldTypeEnum.COMBO.getType().toString(), Arrays.asList(equalCondition));
        map.put(FieldTypeEnum.ADDRESS.getType().toString(), Arrays.asList(equalCondition));
        map.put(FieldTypeEnum.SERIALNO.getType().toString(), Arrays.asList(equalCondition));
        map.put(FieldTypeEnum.COMBO_CHECK.getType().toString(), Arrays.asList(equalCondition));
        map.put(FieldTypeEnum.LABEL.getType().toString(), Arrays.asList(equalCondition));

        map.put(FieldTypeEnum.NUM.getType().toString(), Arrays.asList(rangeCondition));
        map.put(FieldTypeEnum.DATETIME.getType().toString(), Arrays.asList(rangeCondition));

        return map;
    }

}
